package com.zjb.demo.system.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.util.DateUtil;
import com.mybatisflex.solon.service.impl.ServiceImpl;
import com.zjb.demo.common.exception.ServiceException;
import com.zjb.demo.common.util.SecurityUtils;
import com.zjb.demo.system.domain.*;
import com.zjb.demo.system.domain.query.UserQuery;
import com.zjb.demo.system.mapper.*;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.handle.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.mybatisflex.core.query.QueryMethods.distinct;
import static com.mybatisflex.core.query.QueryMethods.findInSet;
import static com.zjb.demo.system.domain.table.SysDeptTableDef.SYS_DEPT;
import static com.zjb.demo.system.domain.table.SysUserRoleTableDef.SYS_USER_ROLE;
import static com.zjb.demo.system.domain.table.UserTableDef.USER;


/**
 * @author 庄佳彬
 * @since 2023/12/22 11:25
 */
@Component
public class UserService extends ServiceImpl<UserMapper, User> {

    private static final Logger log = LoggerFactory.getLogger(UserService.class);
    @Inject
    private SysRoleMapper roleMapper;
    @Inject
    private SysPostMapper postMapper;
    @Inject
    private SysUserRoleMapper userRoleMapper;
    @Inject
    private SysUserPostMapper userPostMapper;

    /**
     * 根据用户名获取用户信息
     *
     * @param username 用户名
     * @return 如果找到对应用户，则返回Optional<User>对象，否则返回空的Optional对象
     */
    public Optional<User> getByUsername(String username) {
        return queryChain()
                .select(USER.ALL_COLUMNS)
                .from(USER)
                .where(USER.USER_NAME.eq(username))
                .one();
    }

    /**
     * 记录登录信息
     *
     * @param id 用户ID
     */
    public void recordLoginInfo(Long id) {
        // 根据用户ID获取用户对象
        var user = getById(id);
        // 更新用户登录IP和登录日期
        updateChain()
                .set(USER.LOGIN_IP, Context.current().realIp())
                .set(USER.LOGIN_DATE, new Date())
                .where(USER.ID.eq(id))
                .update();
    }

    /**
     * 根据用户名选择用户角色组
     *
     * @param username 用户名
     * @return 用户角色组
     */
    public String selectUserRoleGroup(String username) {
        var list = roleMapper.selectRolesByUserName(username);
        if (CollectionUtil.isEmpty(list)) {
            return StrUtil.EMPTY;
        }
        return list.stream()
                .map(SysRole::getRoleName)
                .collect(Collectors.joining(","));

    }

    /**
     * 根据用户名选择用户职位组
     *
     * @param username 用户名
     * @return 选择的用户职位组
     */
    public String selectUserPostGroup(String username) {
        var list = postMapper.selectUserPostGroup(username);

        if (CollectionUtil.isEmpty(list)) {
            return StrUtil.EMPTY;
        }
        return list.stream()
                .map(SysPost::getPostName)
                .collect(Collectors.joining(","));
    }

    /**
     * 判断是否存在指定手机号的用户
     *
     * @param phoneNumber 手机号码
     * @return 如果存在指定手机号的用户则返回true，否则返回false
     */
    public boolean existsByPhone(String phoneNumber) {
        return queryChain()
                .select(USER.ID)
                .from(USER)
                .where(USER.PHONE_NUMBER.eq(phoneNumber))
                .exists();
    }


    /**
     * 判断是否存在指定邮箱的用户
     *
     * @param email 邮箱地址
     * @return 如果存在指定邮箱的用户则返回true，否则返回false
     */
    public boolean existsByEmail(String email) {
        return queryChain()
                .select(USER.ID)
                .from(USER)
                .where(USER.EMAIL.eq(email))
                .exists();
    }

    /**
     * 重置用户密码
     *
     * @param userName 用户名
     * @param pwd      新密码
     * @return 是否成功重置密码
     */
    public boolean resetUserPwd(String userName, String pwd) {
        return updateChain()
                .set(USER.PASSWORD, pwd)
                .where(USER.USER_NAME.eq(userName))
                .update();
    }


    /**
     * 更新用户头像
     *
     * @param username 用户名
     * @param avatar   用户头像
     * @return 更新是否成功
     */
    public boolean updateAvatar(String username, String avatar) {
        return updateChain()
                .set(USER.AVATAR, avatar)
                .where(USER.USER_NAME.eq(username))
                .update();
    }


    /**
     * 检查用户名是否唯一
     *
     * @param sysUser 系统用户对象
     * @return 如果用户名存在，则返回false；否则返回true
     */
    public boolean checkUserNameUnique(User sysUser) {
        return queryChain()
                .select(USER.ID)
                .from(USER)
                .where(USER.USER_NAME.eq(sysUser.getUserName()))
                .exists();
    }

    /**
     * 注册用户
     *
     * @param sysUser 用户对象
     * @return 注册是否成功
     */
    public boolean registerUser(User sysUser) {
        return save(sysUser);
    }

    /**
     * 根据用户名选择用户
     *
     * @param username 用户名
     * @return 如果找到对应用户，则返回 Optional<User> 包含用户对象，否则返回空的 Optional<User>
     */
    public Optional<User> selectUserByUserName(String username) {
        return queryChain()
                .select(USER.ALL_COLUMNS)
                .from(USER)
                .where(USER.USER_NAME.eq(username))
                .one();
    }

    /**
     * 选择已分配的用户列表
     *
     * @param query 用户查询对象
     * @return 分页用户列表
     */
    public Page<User> selectAllocatedList(UserQuery query) {
        var page = new Page<User>(query.getPageNum(), query.getPageSize());
        return queryChain()
                .select(distinct(USER.ID),
                        USER.DEPT_ID,
                        USER.USER_NAME,
                        USER.NICK_NAME,
                        USER.EMAIL,
                        USER.PHONE_NUMBER,
                        USER.SEX,
                        USER.STATUS,
                        USER.CREATE_TIME)
                .from(USER)
                .leftJoin(SYS_USER_ROLE)
                .on(USER.ID.eq(SYS_USER_ROLE.USER_ID))
                .where(SYS_USER_ROLE.ROLE_ID.eq(query.getRoleId()))
                .and(USER.USER_NAME.like(query.getUserName()))
                .and(USER.PHONE_NUMBER.like(query.getPhonenumber()))
                .page(page);
    }


    /**
     * 选择未分配的用户列表
     *
     * @param query 用户查询对象
     * @return 分页用户列表
     */
    public Page<User> selectUnallocatedList(UserQuery query) {
        var page = new Page<User>(query.getPageNum(), query.getPageSize());
        var subQuery = QueryWrapper.create()
                .select(USER.ID)
                .from(USER)
                .join(SYS_USER_ROLE)
                .on(USER.ID.eq(SYS_USER_ROLE.USER_ID).and(SYS_USER_ROLE.ROLE_ID.eq(query.getRoleId())));
        return queryChain()
                .select(distinct(USER.ID),
                        USER.DEPT_ID,
                        USER.USER_NAME,
                        USER.NICK_NAME,
                        USER.EMAIL,
                        USER.PHONE_NUMBER,
                        USER.SEX,
                        USER.STATUS,
                        USER.CREATE_TIME)
                .from(USER)
                .leftJoin(SYS_USER_ROLE)
                .on(USER.ID.eq(SYS_USER_ROLE.USER_ID))
                .where(SYS_USER_ROLE.ROLE_ID.ne(query.getRoleId()).and(SYS_USER_ROLE.ROLE_ID.isNull()))
                .and(USER.ID.notIn(subQuery))
                .and(USER.USER_NAME.like(query.getUserName()))
                .and(USER.PHONE_NUMBER.like(query.getPhonenumber()))
                .page(page);
    }


    /**
     * 根据用户查询条件分页查询用户列表
     *
     * @param query 用户查询对象
     * @return 分页对象
     */
    public Page<User> pageList(UserQuery query) {
        var page = new Page<User>(query.getPageNum(), query.getPageSize());
        var start = DateUtil.parseDate(query.getBeginTime());
        var end = DateUtil.parseDate(query.getEndTime());
        QueryWrapper queryWrapper = null;

        // 根据部门ID生成查询条件
        if (query.getDeptId() != null) {
            queryWrapper = QueryWrapper.create()
                    .select(SYS_DEPT.DEPT_ID)
                    .from(SYS_DEPT)
                    .where(findInSet(String.valueOf(query.getDeptId()), SYS_DEPT.ANCESTORS.getName()).le(0));
        }

        return queryChain()
                .select(USER.DEFAULT_COLUMNS)
                .from(USER)
                .where(USER.ID.eq(query.getUserId(), query.getUserId() != null)) // 根据用户ID过滤
                .and(USER.USER_NAME.like(query.getUserName())) // 根据用户名过滤
                .and(USER.STATUS.eq(query.getStatus())) // 根据用户状态过滤
                .and(USER.PHONE_NUMBER.like(query.getPhonenumber())) // 根据手机号码过滤
                .and(USER.CREATE_TIME.ge(start)) // 根据创建时间范围过滤
                .and(USER.CREATE_TIME.le(end)) // 根据创建时间范围过滤
                .and(USER.DEPT_ID.eq(query.getDeptId())).or(USER.DEPT_ID.in(queryWrapper)) // 根据部门ID过滤
                .withRelations()
                .page(page);
    }

    private void insertPost(User user) {
        var list = user.getPostIds();
        if (CollectionUtil.isNotEmpty(list)) {
            var supList = list.stream()
                    .map(postId -> {
                        var sup = new SysUserPost();
                        sup.setPostId(postId);
                        sup.setUserId(user.getId());
                        return sup;
                    })
                    .toList();
            userPostMapper.insertBatch(supList);
        }
    }

    private void insertRole(User user) {
        var list = user.getRoleIds();
        if (CollectionUtil.isNotEmpty(list)) {
            var supList = list.stream()
                    .map(id -> {
                        var sup = new SysUserRole();
                        sup.setRoleId(id);
                        sup.setUserId(user.getId());
                        return sup;
                    })
                    .toList();
            userRoleMapper.insertBatch(supList);
        }
    }

    /**
     * 保存用户信息
     *
     * @param user 待保存的用户对象
     * @return 保存是否成功的布尔值
     */
    public Boolean saveUser(User user) {
        return Db.txWithResult(() -> {
            var result = save(user);
            insertPost(user);
            insertRole(user);
            return result;
        });
    }


    /**
     * 更新用户信息
     *
     * @param user 待更新的用户对象
     * @return 更新是否成功的结果
     */
    public Boolean updateUser(User user) {
        return Db.txWithResult(() -> {
            // 删除用户的用户角色信息
            userRoleMapper.deleteByUserId(user.getId());
            // 插入新的用户角色信息
            insertRole(user);
            // 删除用户的用户职位信息
            var flag = userPostMapper.deleteByUserId(user.getId());
            log.info("delete post:{}", flag);
            // 插入新的用户职位信息
            insertPost(user);
            // 更新用户的基本信息
            return updateById(user);
        });
    }

    private void checkUserAllowed(Long userId) {
        if (SecurityUtils.isAdmin(userId)) {
            throw new ServiceException("不允许删除超级管理员");
        }
    }

    /**
     * 根据用户ID列表删除用户
     *
     * @param id 用户ID列表
     * @return 删除结果，成功返回true，否则返回false
     */
    public Boolean removeUserByIds(List<Long> id) {
        for (Long userId : id) {
            checkUserAllowed(userId);
        }
        return Db.txWithResult(() -> {
            boolean role = userRoleMapper.deleteByUserIds(id);
            boolean post = userPostMapper.deleteByUserIds(id);
            log.info("delete post:{},delete role:{}", post, role);
            return removeByIds(id);
        });
    }

    public Boolean insertUserAuth(Long userId, Long[] roleIds) {
        boolean role = userRoleMapper.deleteByUserId(userId);
        log.info("delete role:{}", role);
        var list = Stream.of(roleIds)
                .map(roleId -> new SysUserRole(userId, roleId))
                .toList();
        return userRoleMapper.insertBatch(list) > 0;
    }
}
